﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Net;
using SMSROUTER.Business;
using Settings;
using Utils;

namespace PluggableModulesInterface
{
    public abstract class WorkingBaseTimer : IDisposable
    {
        #region Properties and fields
        protected virtual int DUETIME { get { return 1000; } }
        protected virtual int PERIOD { get { return 60000; } }
        
        private object _lock = new object();
        private bool _start = false;
        public bool IsStart
        {
            get
            {
                return _start;
            }
            private set
            {
                lock (_lock)
                {
                    _start = value;
                }
            }

        }
        private Timer timer;
        protected int syncPoint = 0;     
        private Dictionary<string, DateTime> currentException = new Dictionary<string, DateTime>();
        #endregion Properties and fields

        #region SyncLoop
        public virtual void Start()
        {
            lock (_lock)
            {
                Stop();
                IsStart = true;
                timer = new Timer(CycleLoop, null, DUETIME, PERIOD);
            }
        }

        public virtual void Stop()
        {
            lock (_lock)
            {
                IsStart = false;
                if (timer != null)
                {
                    timer.Dispose();
                }
            }
        }

        protected void ChangeTimer(int dueTime, int period)
        {
            if (timer != null)
            {
                timer.Change(dueTime, period);
            }
        }

        private void CycleLoop(object state)
        {
            try
            {
                LoopWorking();
            }
            catch (Exception ex)
            {
                HandleException(ex, "WorkingBaseTimer");
            }
            finally
            {
                syncPoint = 0;
            }
        }

        protected abstract void LoopWorking();
        #endregion

        #region Handle Exception
        /// <summary>
        /// Xử lý Exception chung
        /// </summary>
        protected virtual void HandleException(Exception ex, string logType)
        {
            string hashEx = ex.Message.ToMD5Hash();
            if (!currentException.ContainsKey(hashEx))
            {
                currentException.Add(hashEx, DateTime.Now);
                Log.InsertLog(ex, logType, null);
            }
            else if (DateTime.Now - currentException[hashEx] >= TimeSpan.FromSeconds(AppSetting.DurationAlertRouter))
            {
                Log.InsertLog(ex, logType, null);
                currentException[hashEx] = DateTime.Now;
            }
            if (currentException.Count > 1000)
                currentException.Clear();
        }
        #endregion Handle Exception

        #region Disposable
        // A base class that implements IDisposable. 
        // By implementing IDisposable, you are announcing that 
        // instances of this type allocate scarce resources. 

        // Pointer to an external unmanaged resource. 
        private IntPtr Ptrhandle;
        // Track whether Dispose has been called. 
        private bool disposed = false;

        // Implement IDisposable. 
        // Do not make this method virtual. 
        // A derived class should not be able to override this method. 
        public void Dispose()
        {
            Dispose(true);
            // This object will be cleaned up by the Dispose method. 
            // Therefore, you should call GC.SupressFinalize to 
            // take this object off the finalization queue 
            // and prevent finalization code for this object 
            // from executing a second time.
            GC.SuppressFinalize(this);
        }

        // Dispose(bool disposing) executes in two distinct scenarios. 
        // If disposing equals true, the method has been called directly 
        // or indirectly by a user's code. Managed and unmanaged resources 
        // can be disposed. 
        // If disposing equals false, the method has been called by the 
        // runtime from inside the finalizer and you should not reference 
        // other objects. Only unmanaged resources can be disposed. 
        protected virtual void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called. 
            if (!this.disposed)
            {
                // If disposing equals true, dispose all managed 
                // and unmanaged resources. 
                if (disposing)
                {
                    // Dispose managed resources.
                    Stop();
                }

                // Call the appropriate methods to clean up 
                // unmanaged resources here. 
                // If disposing is false, 
                // only the following code is executed.
                CloseHandle(Ptrhandle);
                Ptrhandle = IntPtr.Zero;

                // Note disposing has been done.
                disposed = true;
            }
        }

        // Use interop to call the method necessary 
        // to clean up the unmanaged resource.
        [System.Runtime.InteropServices.DllImport("Kernel32")]
        private extern static Boolean CloseHandle(IntPtr handle);
        #endregion Dispose
    }
}
